; program to print instructions for "Towers of Hanoi" puzzle
; author:  R. Detmer   revised:  10/97

.386
.MODEL FLAT

ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

include io.h            ; header file for input/output

cr      equ     0dh     ; carriage return character
Lf      equ     0ah     ; line feed

.STACK  4096            ; reserve 4096-byte stack

.DATA                   ; reserve storage for data
prompt      BYTE   cr,Lf,'How many disks?  ',0
number      BYTE   16 DUP (?)
message     BYTE   cr,Lf,'Move disk from spindle '
source      BYTE   ?
            BYTE   ' to spindle '
dest        BYTE   ?
            BYTE   '.',0
.CODE
Move        PROC NEAR32
; procedure Move(NbrDisks : integer; { number of disks to move }
;                Source, Dest, Spare : character { spindles to use } )
; parameters are passed in words on the stack

            push   ebp           ; save base pointer
            mov    ebp,esp       ; copy stack pointer
            push   eax           ; save registers
            push   ebx

            cmp    WORD PTR [ebp+14],1  ; NbrDisks = 1?
            jne    elseMore      ; skip if more than 1
            mov    bx,[ebp+12]   ; Source
            mov    source,bl     ; copy character to output
            mov    bx,[ebp+10]   ; destination
            mov    dest,bl       ; copy character to output
            output message       ; print line
            jmp    endIfOne      ; return
elseMore:   mov    ax,[ebp+14]   ; get NbrDisks
            dec    ax            ; NbrDisks - 1
            push   ax            ; parameter 1: NbrDisks-1
            pushw  [ebp+12]      ; parameter 2: source does not change
            pushw  [ebp+8]       ; parameter 3: old spare is new destination
            pushw  [ebp+10]      ; parameter 4: old destination is new spare
            call   Move          ; Move(NbrDisks-1,Source,Spare,Destination)
            add    esp,8         ; remove parameters from stack

            pushw  1             ; parameter 1: 1
            pushw  [ebp+12]      ; parameter 2: source does not change
            pushw  [ebp+10]      ; parameter 3: destination unchanged
            pushw  [ebp+8]       ; parameter 4: spare unchanged
            call   Move          ; Move(1,Source,Destination,Spare)
            add    esp,8         ; remove parameters from stack

            push   ax            ; parameter 1: NbrDisks-1
            pushw  [ebp+8]       ; parameter 2: source is original spare
            pushw  [ebp+10]      ; parameter 3: original destination
            pushw  [ebp+12]      ; parameter 4: original source is spare
            call   Move          ; Move(NbrDisks-1,Spare,Destination,Source)
            add    esp,8         ; remove parameters from stack
endIfOne:
            pop    ebx           ; restore registers
            pop    eax
            pop    ebp           ; restore base pointer
            ret                  ; return
Move        ENDP

_start:     output prompt       ; ask for number of disks
            input  number,16    ; read ASCII characters
            atoi   number       ; convert to integer
            push   ax           ; argument 1: Number
            mov    al,'A'       ; argument 2: ' A'
            push   ax
            mov    al,'B'       ; argument 3: ' B'
            push   ax
            mov    al,'C'       ; argument 4: ' C'
            push   ax
            call   Move         ; Move(Number,Source,Dest,Spare)
            add    esp,8        ; remove parameters from stack

            INVOKE  ExitProcess, 0  ; exit with return code 0

PUBLIC _start                   ; make entry point public
END                             ; end of source code

